package main

import "fmt"

/*
接口介绍
	Go语言的类型都是【隐式实现】接口的，任何定义了接口中【所有方法】的类型都被称为隐式地实现了该接口
*/
func main() {

	/*
		一. 1. 定义接口语法格式：
				type 接口名 interface {
					方法1([参数列表]) [返回值]
					方法2([参数列表]) [返回值]
					方法3([参数列表]) [返回值]
					...
				}
			2. 实现接口方法语法格式：
				func (变量名 结构体类型) 接口方法1([参数列表]) [返回值]{
					// 方法体
				}
				func (变量名 结构体类型) 接口方法2([参数列表]) [返回值]{
						// 方法体
				}
	*/

	apple := Apple{Model: "iphone8"}
	apple.call()
	g := Google{model: "pexil4"}
	g.call()

	/*
		二. duck typing。duck typing是描述事物的外部行为而非内部结构。
			使用duck typing的编程语言往往被归类为“动态类型语言”或者“解释型语言”，如Python、Javascript、Ruby等；而非duck typing编程语言往往被
			归为“静态类型语言”，如C、C++、Java等。

			TIPS：动态类型语言的好处很多，Python代码写起来很快。但是缺陷也是显而易见的：错误往往要在运行时才能被发现。Go类型系统采取了折中的办法，
				  其做法如下：
					· 结构体类型T不需要显式地声明它实现了接口I。只要类型T实现了接口I规定的【所有方法】，它就自动地实现了接口I。
					  这样就像动态类型语言一样省了很多代码，少了许多限制；
					· 将结构体类型的变量显式或者隐式地转换为接口I类型的变量i。这样就可以和其他静态类型语言一样，在编译时检查参数的合法性
	*/

	fmt.Println(apple.sayHello())
	fmt.Println(g.sayHello())

	/*
		三. 一个函数如果接受接口类型作为参数，那么实际上它可以传入该接口的任意一个实现类的对象作为参数。
			定义一个接口变量，实际上可以赋值给任意一个实现了该接口的对象。如果定义了一个接口类型的容器（数组或切片），
			实际上该容器可以存储任意一个实现类对象
	*/
	var i IPhone // TIPS：接口变量包括了实现者的类型和实现者的值或指针，通过inspect()函数打印结果可以验证这一点
	i = &apple
	inspect(i)
	isApple(i)
	i = g
	inspect(i)
	isApple(i)
}

func isApple(i IPhone) {

	// 类型断言
	if i2, ok := i.(*Apple); ok {
		fmt.Println("this is apple：", i2.Model)
	} else {
		fmt.Println("this is not apple:")
	}
}

func inspect(i IPhone) {

	// 类型判断
	switch v := i.(type) {
	case *Apple:
		fmt.Printf("%T， %v, %p \n", i, i, i)
		fmt.Println(v.Model)
		v.call()
	case Google:
		fmt.Printf("%T， %v, %p \n", i, i, &i)
		fmt.Println(v.model)
		v.call()
	}
}

/*
定义接口
*/
type IPhone interface {
	call()
	sayHello() string
}

type Apple struct {
	Model string
}

type Google struct {
	model string
}

func (apple *Apple) call() {

	fmt.Println("我是苹果手机，型号：", apple.Model)
}

func (google Google) call() {

	fmt.Println("我是谷歌手机，型号：", google.model)
}

func (apple Apple) sayHello() string {

	return "hello，我是：" + apple.Model
}

func (google Google) sayHello() string {

	return "hello，我是：" + google.model
}
